package com.rojored.remote
{

import com.rojored.remote.dsDelegateTestHelpers.ObjectA;
import com.rojored.remote.dsDelegateTestHelpers.ObjectB;
import mx.utils.ObjectUtil;
import org.flexunit.assertThat;
import org.hamcrest.collection.array;
import org.hamcrest.core.not;
import org.hamcrest.object.equalTo;
import org.hamcrest.object.hasProperties;
import org.hamcrest.object.hasProperty;

/**
 *  Tests for basic DSDelegate functionality
 */
public class DSDelegateTest
{

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor
     */
    public function DSDelegateTest()
    {
        super();
    }

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private var dsDelegate:DSDelegate;

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    [Before]

    /**
     *  Reset the delegate instance.
     */
    public function resetDelegate():void
    {
        dsDelegate = new DSDelegate();
    }

    [After]

    /**
     *  Clear delegate reference
     */
    public function clear():void
    {
        dsDelegate = null;
    }

    [Test(description="Test basic parameter encoding")]

    /**
     *  Test basic property enconding for parameters.
     */
    public function testAttributeEncoding():void
    {
        var objectA:ObjectA = new ObjectA();
        var valueA:String = "a value a";
        var valueB:Number = 5234;
        objectA.propertyA = valueA;
        objectA.propertyB = valueB;
        var attributesResult:Object = dsDelegate.toAttributes(objectA);
        assertThat(
            "properties a and b are properly encoded",
            attributesResult,
            hasProperties({propertyA: valueA, propertyB: valueB})
        );
    }

    [Test(description="Attributes marked for ignore shouldn't be parametrized")]

    /**
     *  Test attribute ignore for.
     */
    public function attributesMarkedForIgnoredArIgnored():void
    {
        var objectA:ObjectA = new ObjectA();
        objectA.convenienceProperty = "convenience property value";
        objectA.transientProperty = "transient property value";
        var attributesResult:Object = dsDelegate.toAttributes(objectA);

        assertThat(
            "Transient properties shouldn't be parametrized",
            attributesResult,
            not(hasProperty("transientProperty"))
        );

        assertThat(
            "Convenience properties shouldn't be parametrized",
            attributesResult,
            not(hasProperty("convenienceProperty"))
        );
    }

    [Test(description="Illegal referenced item with no id",
          expects="com.rojored.remote.errors.NoIdPropertyError")]

    /**
     *   Test illegal referenced item with no id.
     */
    public function illegalReferencedItemWithNoId():void
    {
        var objectA:ObjectA = new ObjectA();
        var anotherObjectA:ObjectA = new ObjectA();
        objectA.referencedPropertyA  = anotherObjectA;
        var attributesResult:Object = dsDelegate.toAttributes(objectA);
    }

    [Test(description="Referenced property id is encoded correctly")]
    
    /**
     *   Test that referenced the id of a Reference property is encoded fine.
     */
    public function testReferencePropertyIdEncoded():void
    {
        var objectBId:String = "xx0101";
        var objectA:ObjectA = new ObjectA();
        var objectB:ObjectB = new ObjectB();
        objectB.id = objectBId;
        objectA.refeferencedPropertyB = objectB;
        var attributesResult:Object = dsDelegate.toAttributes(objectA);
        assertThat(
            "Referenced object id is sent correctly as attribute.",
            attributesResult,
            hasProperty("refeferencedPropertyB", objectBId)
        );
    }

    [Test(description="A list of referenced objects is encoded correctly")]
    
    /**
     *  Test that a list of refrence objects is encoded fine.
     */
    public function listOfReferenceObjectsEncodedCorrectly():void
    {
        var objectA:ObjectA = new ObjectA();
        objectA.listOfReferences = [
            new ObjectB("A1"),
            new ObjectB("A2"),
            new ObjectB("A3")
        ];
        var attributesResult:Object = dsDelegate.toAttributes(objectA);
        assertThat(
            "List of references is parametrized",
            attributesResult.listOfReferences,
            array("A1", "A2", "A3")
        );
    }

    [Test(description="Illegal referenced item within reference list with no id",
          expects="com.rojored.remote.errors.NoIdPropertyError")]
    
    /**
     *   Test illegal values in reference list are detected and raised.
     */
    public function chokeOnInvalidNestedReferences():void
    {
        var objectA:ObjectA = new ObjectA();
        objectA.listOfReferences = [
            new ObjectB("A1"),
            new ObjectB("A2"),
            new ObjectA(),
            new ObjectB("A3"),
            new ObjectB("A4")
        ];
        var attributesResult:Object = dsDelegate.toAttributes(objectA);
    }
}
}
